/* *********************************************************************************  
 *   This file is part of GeometryPlayground.
 *
 *   GeometryPlayground is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   GeometryPlayground is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with GeometryPlayground.  If not, see <http://www.gnu.org/licenses/>.
 **********************************************************************************/
 
import java.io.*;
import java.util.LinkedList;
import java.util.Scanner;
import javax.swing.*;
import jpsxdec.FileNameExtensionFilter;

public final class SaveLoad{
	static String lastDirectory=null;

  public static void save(LinkedList<GeoConstruct>list,GeoCanvas parent) {
    JFileChooser saveDlg=new JFileChooser(lastDirectory);
    saveDlg.setFileFilter(parent.geometry.getFileFilter());
    int retval = saveDlg.showSaveDialog(parent);
    if (retval == JFileChooser.APPROVE_OPTION) {
      //... The user selected a file, get it, use it.
      String fileName=saveDlg.getName(saveDlg.getSelectedFile());
      String dirName=saveDlg.getSelectedFile().getPath();
      lastDirectory=dirName;
      PrintWriter outFile;

      if(((FileNameExtensionFilter)(parent.geometry.getFileFilter())).accept(saveDlg.getSelectedFile()))
        fileName=dirName;
      else
        fileName=dirName+"."+parent.geometry.extension();
      try {
        outFile = new PrintWriter(new FileWriter(fileName),true);
        outFile.println("Geometry:"+parent.geometry.getName());
        outFile.println("!KEY:ID,Type,<x,y,z>,{parent-1,parent-2,...},isShown,hasLabel,isReal");
        for (int i=0;i<list.size();i++){
          String strObj="";
          strObj+= list.get(i).ID+",";
          strObj+= TypeToString(list.get(i).type);
          strObj+=",<"+list.get(i).getX()+","+list.get(i).getY()+","+list.get(i).getZ()+">,";
          strObj+="{";
          for(int j=0;j<list.get(i).constList.size();j++){
            System.out.println(list.get(i).constList.size());
            strObj+=list.get(i).get(j).getID();
            if(j<list.get(i).constList.size()-1) 
              strObj+=",";
          }
          strObj+="},";
          strObj+=list.get(i).shown+","+list.get(i).labelShown+","+list.get(i).isReal;
          if(i<(list.size()-1))strObj+="\n";
          outFile.print(strObj);
        }
        outFile.close();      
      } catch (IOException e) {
        JOptionPane.showMessageDialog(parent,"File Error: "+e.toString());

        //System.err.println("File Error: "+e.toString());
        //System.exit(1);
      }
    }

  }
  // end save method

  // method to load info from a text file
  public static void load(LinkedList<GeoConstruct>list,GeoCanvas parent) {
    try{
      JFileChooser openDlg=new JFileChooser(lastDirectory);
      openDlg.setFileFilter(parent.geometry.getFileFilter());
      //For the Time being, Clear the list before loading
      list.clear();
      int retval=-1;

      retval = openDlg.showOpenDialog(parent);

      if (retval == JFileChooser.APPROVE_OPTION) {
        //... The user selected a file, get it, use it.
        Scanner scanner = new Scanner(openDlg.getSelectedFile());
        lastDirectory=openDlg.getSelectedFile().getPath();
        try {
          list.size();
          //Check the first line for geometry

          if(processGeometry(scanner.nextLine(),parent.geometry.getName()))
            throw new IOException("The File you are trying to open does not match the geometry.");
          //first use a Scanner to get each line
          while ( scanner.hasNextLine() ){
            processLine(scanner.nextLine(),list,parent.geometry);
          }
        } 
        catch (Exception e){
          throw e;
        }
        finally {
          //ensure the underlying stream is always closed
          scanner.close();
        }

      }
    }
    catch (Exception e){
      JOptionPane.showMessageDialog(parent,"File Error: "+e.toString());
    }
  }
  // end load method

  private static boolean processGeometry(String aLine, String GeoName){
    Scanner scanner = new Scanner(aLine);
    scanner.useDelimiter(":");
    scanner.next();
    String Geometry=scanner.next();
    return (!Geometry.equals(GeoName));

  }
  private static void processLine(String aLine,LinkedList<GeoConstruct>list, GeoMetry geometry){
    Scanner scanner = new Scanner(aLine);
    //String isComment=scanner.findInLine("!");
    if(scanner.findInLine("!")==null){
      scanner.useDelimiter(",");
      LinkedList<GeoConstruct> parentList =new LinkedList<GeoConstruct>();

      int ID=scanner.nextInt();
      String typeStr=scanner.next();
      int type=StringToType(typeStr);
      double[] vector1={0,0,0};
      String temp=scanner.next();

      vector1[0]=Double.valueOf(temp.substring(1));
      vector1[1]=scanner.nextDouble();
      temp=scanner.next();
      vector1[2]=Double.valueOf(temp.substring(0, temp.length()-1));

      /*************New Improved parentList code*****************/
      int cID;
      temp=scanner.next();
      if(!temp.equals("{}")){
        temp=temp.substring(1);
        //cID=Integer.valueOf(temp.substring(1));
        while(true){
          //parentList.addLast(list.get(cID));
          //temp=scanner.next();
          if(temp.contains("}")){
            cID=Integer.valueOf(temp.substring(0,temp.length()-1));
            parentList.addLast(list.get(cID));
            break;
          }
          else{
            cID=Integer.valueOf(temp);
            parentList.addLast(list.get(cID));
          }
          temp=scanner.next();
        }
      }
      /********************************************/
      /**********Legacy code below      
      int iA,iB=-1;
      String A=scanner.next();
      if(!A.equals("null")) iA=Integer.valueOf(A);
      String B=scanner.next();
      if(!B.equals("null")) iB=Integer.valueOf(B);
       ****************************************/
      GeoConstruct listItem=null;
      double[] v={0,0,0};
      switch(type){
      case GeoConstruct.LINE:
      case GeoConstruct.PERP:
      case GeoConstruct.SEGMENT:
	  case GeoConstruct.BISECTOR:
        listItem=geometry.createLine(type, parentList);
		listItem.setXYZ(vector1);
        break; 

      case GeoConstruct.CIRCLE:
        listItem=geometry.createCircle(parentList.get(0), parentList.get(1));
		listItem.setXYZ(vector1);
        break;

      case GeoConstruct.POINT:
      case GeoConstruct.FIXedPT:
      case GeoConstruct.PTonLINE:
      case GeoConstruct.PTonCIRC:
	  case GeoConstruct.MIDPT:
      case GeoConstruct.DISTANCE:
      case GeoConstruct.CIRCUMF:
      case GeoConstruct.AREA:
      case GeoConstruct.RATIO:
	  case GeoConstruct.ANGLE:
	  case GeoConstruct.LINEintLINE0:
      case GeoConstruct.CIRCintLINE0:
      case GeoConstruct.CIRCintCIRC00:
      case GeoConstruct.LINEintLINE1: 
      case GeoConstruct.CIRCintLINE1:
      case GeoConstruct.CIRCintCIRC01:
      case GeoConstruct.CIRCintCIRC10:
      case GeoConstruct.CIRCintCIRC11:
    	for (int i=0;i<3;i++) v[i]=vector1[i];
        listItem=geometry.createPoint(type,parentList,vector1);
		listItem.setXYZ(v);
        break;
	  /*case GeoConstruct.LINEintLINE0:
      case GeoConstruct.CIRCintLINE0:
      case GeoConstruct.CIRCintCIRC00:
      case GeoConstruct.LINEintLINE1: 
      case GeoConstruct.CIRCintLINE1:
      case GeoConstruct.CIRCintCIRC01:
      case GeoConstruct.CIRCintCIRC10:
      case GeoConstruct.CIRCintCIRC11:
    	geometry.createIntersections(parentList.get(0),parentList.get(1),list);
    	list.getLast().setShown(scanner.next().equals("true"));
    	list.getLast().setLabelShown(scanner.next().equals("true"));
    	list.getLast().setValid(scanner.next().equals("true"));
    	listItem=null;
        break;*/

      }
      if(listItem!=null){
        listItem.ID=ID;
        listItem.shown=(scanner.next().equals("true"));
        listItem.labelShown=(scanner.next().equals("true"));
        listItem.isReal=(scanner.next().equals("true"));
        list.add(listItem);
      }
    }
    else{
      scanner.nextLine();
    }
  }

  private static int StringToType(String type){
    if(type.equals("POINT")) return GeoConstruct.POINT;
    if(type.equals("PTonLINE")) return GeoConstruct.PTonLINE;
    if(type.equals("PTonCIRC")) return GeoConstruct.PTonCIRC;
    if(type.equals("LINE")) return GeoConstruct.LINE;
    if(type.equals("PERP")) return GeoConstruct.PERP;
    if(type.equals("SEGMENT")) return GeoConstruct.SEGMENT;
    if(type.equals("CIRCLE")) return GeoConstruct.CIRCLE;
    if(type.equals("LINEintLINE0")) return GeoConstruct.LINEintLINE0;
    if(type.equals("LINEintLINE1")) return GeoConstruct.LINEintLINE1;
    if(type.equals("CIRCintLINE0")) return GeoConstruct.CIRCintLINE0;
    if(type.equals("CIRCintLINE1")) return GeoConstruct.CIRCintLINE1;
    if(type.equals("CIRCintCIRC00")) return GeoConstruct.CIRCintCIRC00;
    if(type.equals("CIRCintCIRC01")) return GeoConstruct.CIRCintCIRC01;
    if(type.equals("CIRCintCIRC10")) return GeoConstruct.CIRCintCIRC10;
    if(type.equals("CIRCintCIRC11")) return GeoConstruct.CIRCintCIRC11;
    if(type.equals("MIDPT")) return GeoConstruct.MIDPT;
    if(type.equals("FIXedPT")) return GeoConstruct.FIXedPT;
    if(type.equals("DISTANCE")) return GeoConstruct.DISTANCE;
    if(type.equals("CIRCUMFERENCE")) return GeoConstruct.CIRCUMF;
    if(type.equals("AREA")) return GeoConstruct.AREA;
    if(type.equals("RATIO")) return GeoConstruct.RATIO;
	if(type.equals("ANGLE")) return GeoConstruct.ANGLE;
	if(type.equals("BISECTOR")) return GeoConstruct.BISECTOR;
    else return 200;
  }

  private static String TypeToString(int type){
    switch(type){

    case GeoConstruct.POINT:			return "POINT";
    case GeoConstruct.PTonLINE:			return "PTonLINE";
    case GeoConstruct.PTonCIRC:			return "PTonCIRC";
    case GeoConstruct.LINE:				return "LINE";
    case GeoConstruct.PERP:				return "PERP";
    case GeoConstruct.SEGMENT:			return "SEGMENT";
    case GeoConstruct.CIRCLE:			return "CIRCLE";
    case GeoConstruct.LINEintLINE0:		return "LINEintLINE0";
    case GeoConstruct.LINEintLINE1:		return "LINEintLINE1";
    case GeoConstruct.CIRCintLINE0:		return "CIRCintLINE0";
    case GeoConstruct.CIRCintLINE1:		return "CIRCintLINE1";
    case GeoConstruct.CIRCintCIRC00:	return "CIRCintCIRC00";
    case GeoConstruct.CIRCintCIRC01:	return "CIRCintCIRC01";
    case GeoConstruct.CIRCintCIRC10:	return "CIRCintCIRC10";
    case GeoConstruct.CIRCintCIRC11:	return "CIRCintCIRC11";
    case GeoConstruct.MIDPT:			return "MIDPT";
    case GeoConstruct.FIXedPT:			return "FIXedPT";
    case GeoConstruct.DISTANCE:			return "DISTANCE";
    case GeoConstruct.CIRCUMF:			return "CIRCUMFERENCE";
    case GeoConstruct.AREA:				return "AREA";
    case GeoConstruct.RATIO:			return "RATIO";
	case GeoConstruct.ANGLE:			return "ANGLE";
	case GeoConstruct.BISECTOR:			return "BISECTOR";
    default: return "Nothing";

    }

  }
}
